/*
 * Copyright (c) 2025 李伟国
 * SQL-API is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package com.moyu.sql.core.engine.impl;

import com.moyu.sql.core.engine.MoyuSqlSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.exceptions.TooManyResultsException;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

@Slf4j
@Component
public class MoyuSqlSessionDefaultImpl implements MoyuSqlSession {

    private XMLLanguageDriver languageDriver;

    private SqlSessionFactory sqlSessionFactory;

    /**
     * 设置 XMLLanguageDriver
     *
     * @param xmlLanguageDriver XMLLanguageDriver
     */
    @Autowired
    public void setMybatisXMLLanguageDriver(XMLLanguageDriver xmlLanguageDriver) {
        this.languageDriver = xmlLanguageDriver;
    }

    /**
     * 获取 SqlSessionFactory
     *
     * @param sqlSessionFactory SqlSessionFactory
     */
    @Autowired
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    /**
     * 获取 Configuration
     *
     * @return Configuration
     */
    public Configuration getConfiguration() {
        return sqlSessionFactory.getConfiguration();
    }

    /**
     * 构建MappedStatement
     *
     * @param sqlTemplate 动态sql模版
     * @return MappedStatement
     */
    protected MappedStatement buildMappedStatement(String sqlId, String sqlTemplate, SqlCommandType sqlCommandType) {
        String dynamicSql = "<script>" + sqlTemplate + "</script>";
        SqlSource sqlSource = languageDriver.createSqlSource(this.getConfiguration(), dynamicSql, Map.class);

        return new MappedStatement.Builder(this.getConfiguration(), sqlId, sqlSource, sqlCommandType)
                .resultMaps(Collections.singletonList(buildResultMap(sqlId)))
                .build();
    }

    /**
     * 构建 ResultMap
     *
     * @param sqlId sqlId
     * @return ResultMap
     */
    protected ResultMap buildResultMap(String sqlId) {
        List<ResultMapping> resultMappings = Collections.emptyList();
        return new ResultMap.Builder(
                this.getConfiguration(),
                sqlId + "_ResultMap", // 结果映射 ID（唯一）
                Map.class,
                resultMappings
        ).build();
    }

    /**
     * 添加MappedStatement
     *
     * @param sqlId          sqlId
     * @param sqlTemplate    sql模版
     * @param sqlCommandType sql命令类型
     */
    public synchronized void addMappedStatement(String sqlId, String sqlTemplate, SqlCommandType sqlCommandType) {
        this.getConfiguration()
                .addMappedStatement(buildMappedStatement(sqlId, sqlTemplate, sqlCommandType));
    }

    /**
     * 更新MappedStatement
     *
     * @param sqlId          sqlId
     * @param sqlTemplate    sql语句
     * @param sqlCommandType sql命令类型
     */
    @Override
    public synchronized void updateMappedStatement(String sqlId, String sqlTemplate, SqlCommandType sqlCommandType) {
        // 获取Configuration
        Configuration configuration = this.getConfiguration();
        // 通过反射移除旧的MappedStatement
        try {
            this.getConfiguration().getMappedStatementNames().remove(sqlId);
        } catch (Exception e) {
            log.error("MappedStatement更新失败", e);
        }
        // 创建新的MappedStatement
        MappedStatement newMappedStatement = buildMappedStatement(sqlId, sqlTemplate, sqlCommandType);

        configuration.addMappedStatement(newMappedStatement);

        // 清除缓存
        Cache cache = newMappedStatement.getCache();
        if (cache != null) {
            cache.clear();
        }
    }

    /**
     * 执行 sql
     *
     * @param sqlId     sqlId
     * @param paramsMap 参数
     * @return 查询列表
     */
    @Override
    public <E> java.util.List<E> selectList(String sqlId, Map<String, Object> paramsMap) {
        try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
            return sqlSession.selectList(sqlId, paramsMap);
        }
    }


    /**
     * 执行插入 sql
     *
     * @param sqlId     sqlId
     * @param paramsMap 参数
     * @return 插入数量
     */
    @Override
    public int insert(String sqlId, Map<String, Object> paramsMap) {
        try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
            return sqlSession.insert(sqlId, paramsMap);
        }
    }

    /**
     * 执行更新 sql
     *
     * @param sqlId     sqlId
     * @param paramsMap 参数
     * @return 更新数量
     */
    @Override
    public int update(String sqlId, Map<String, Object> paramsMap) {
        try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
            return sqlSession.update(sqlId, paramsMap);
        }
    }

    /**
     * 执行删除 sql
     *
     * @param sqlId     sqlId
     * @param paramsMap 参数
     * @return 删除数量
     */
    @Override
    public int delete(String sqlId, Map<String, Object> paramsMap) {
        try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
            return sqlSession.delete(sqlId, paramsMap);
        }
    }

    /**
     * 执行查询 sql
     *
     * @param sqlId     sqlId
     * @param paramsMap 参数
     * @return 查询结果
     */
    @Override
    public <T> T selectOne(String sqlId, Map<String, Object> paramsMap) throws TooManyResultsException {
        try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
            return sqlSession.selectOne(sqlId, paramsMap);
        }
    }

}
